#pragma once
#include <iostream>
#include <exception>

using namespace std;

class ArrayIndexOutOfBounds
{
	friend std::ostream &operator <<(std::ostream &os, const ArrayIndexOutOfBounds &e);
public:
	ArrayIndexOutOfBounds(const std::string &message) : message(message) {}
	std::string message;
};

class ArrayIterator
{
	friend std::ostream &operator <<(std::ostream &os, const ArrayIterator &array);
public:
	ArrayIterator(int *current, int *beyondLast) :
      current(current),
      beyondLast(beyondLast)
   {
   }

	int &operator *()
   {
      if (current == beyondLast)
         throw ArrayIndexOutOfBounds("Failed to dereference beyond last array element");
      return *current;
   }

	ArrayIterator operator ++();
	bool operator ==(const ArrayIterator &other) {return current == other.current;} 
	bool operator !=(const ArrayIterator &other) {return !(*this == other);}
private:
	int *current;
	int *beyondLast;
};

class Array
{
	friend std::ostream &operator <<(std::ostream &os, const Array &array);
public:
	Array(int size, int *arr = 0);
	~Array();
   Array& Array::operator= (const Array & other);
	int length() const { return size; }
	ArrayIterator begin() {return ArrayIterator(buffer, buffer + size);}
	ArrayIterator end() {return ArrayIterator(buffer + size, buffer + size);}
private:
	int *buffer;
	int size;
};
